Fox's Git Mirrors
π Files β’ βΈ Work (0) β’ πΉ Commits (454) β’ β Branches (2) β’ β Tags (56) β’ β₯ Thanks (0)
>LXMFy
Easily create LXMF bots for the Reticulum Network with this extensible framework.
Feature
ββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Category β Key Capabilities β
ββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Core β Interactive CLI, Command Prefixes, Cron-style Task Scheduler, Middleware & Eventβ¦ β
β Connectivity β Direct Delivery & Propagation Fallback, Auto-Peering, RNS Link Support, Opportunβ¦ β
β Security β Spam Protection, Role-based Permissions, Identity Pinning, Message Signing/Verifβ¦ β
β NLP β Local NLP Intent Classification (Offline/Private), Type-hinted Argument Parsing β
β Extensions β Python Cogs, External Script Cogs (Bash, Go, C, etc.), Linux Sandboxing (Landlocβ¦ β
β Storage β Extensible Backends (JSON, SQLite, In-Memory), Message Persistence (Crash Recoveβ¦ β
β Reliability β Extensive Stability & Mathematical Stress Testing, Chaos Engineering, Resource Lβ¦ β
β UX β Help on First Message, Auto-generated Help Menus, Customizable Bot Icons, Attachβ¦ β
ββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Installation
There are many ways to install LXMFy, you pick:
From PyPI
T282828
# pip
pip install lxmfy
# pipx
pipx install lxmfy
Development Installation
For development, clone the repository and install with poetry:
T282828
git clone https://git.quad4.io/LXMFy/LXMFy.git
cd LXMFy
T282828
poetry install
Usage
T282828
lxmfy
Create bots:
T282828
lxmfy create
Debug send/receive:
T282828
lxmfy debug
lxmfy debug --config ./config --output ./lxmfy-debug-report.txt
lxmfy debug probe <destination_hash> --request-path --wait 30
lxmfy debug send <destination_hash>
lxmfy debug receive
lxmfy debug compare <hash_a> <hash_b>
Doctor mode prints a verdict and next steps, then categorized checks (OS, shared vs owned instance, disk permissions, interfaces, announce, send pipeline / storage history, receive readiness). It saves a privacy-redacted T383838lxmfy-debug-*.txt you can share. Colors auto-disable when not a TTY, when T383838NO_COLOR is set, or when Windows VT is unavailable. Use T383838--no-color or T383838NO_COLOR=1 for plain output.
Docker
Building Manually
To build the Docker image, navigate to the root of the project and run:
T282828
docker build -t lxmfy-test .
Once built, you can run the Docker image:
T282828
docker run -d \\
--name lxmfy-test-bot \\
-v $(pwd)/config:/bot/config \\
-v $(pwd)/.reticulum:/root/.reticulum \\
--restart unless-stopped \\
lxmfy-test
Auto-Interface support (network host):
T282828
docker run -d \\
--name lxmfy-test-bot \\
--network host \\
-v $(pwd)/config:/bot/config \\
-v $(pwd)/.reticulum:/root/.reticulum \\
--restart unless-stopped \\
lxmfy-test
Building Wheels with docker/Dockerfile.Build
The T383838docker/Dockerfile.Build is used to build the T383838lxmfy Python package into a wheel file within a Docker image.
T282828
docker build -f docker/Dockerfile.Build -t lxmfy-wheel-builder .
This will create an image named T383838lxmfy-wheel-builder. To extract the built wheel file from the image, you can run a container from this image and copy the T383838dist directory:
T282828
docker run --rm -v "$(pwd)/dist_output:/output" lxmfy-wheel-builder
This command will create a T383838dist_output directory in your current working directory and copy the built wheel file into it.
Example
T282828
from lxmfy import LXMFBot, load_cogs_from_directory
bot = LXMFBot(
name="LXMFy Test Bot", # Name of the bot that appears on the network.
announce=5400, # Announce every hour, set to 0 to disable.
announce_enabled=True, # Set to False to disable all announces (both initial and periodic)
announce_immediately=True, # Set to False to disable initial announce
admins=["your_lxmf_hash_here"], # List of admin hashes.
hot_reloading=True, # Enable hot reloading.
command_prefix="/", # Set to None to process all messages as commands.
cogs_dir="cogs", # Specify cogs directory name.
rate_limit=5, # 5 messages per minute
cooldown=5, # 5 seconds cooldown
max_warnings=3, # 3 warnings before ban
warning_timeout=300, # Warnings reset after 5 minutes
signature_verification_enabled=True, # Enable cryptographic signature verification
require_message_signatures=False, # Allow unsigned messages but log them
propagation_fallback_enabled=True, # Enable propagation fallback after direct delivery fails
propagation_node="your_propagation_node_hash_here", # Manual propagation node (optional)
autopeer_propagation=True, # Auto-discover propagation nodes (optional)
autopeer_maxdepth=4, # Max hops for auto-peering (default: 4)
enable_propagation_node=False, # Run as propagation node (default: False)
message_storage_limit_mb=500, # Storage limit in MB for propagation node (default: 500)
direct_delivery_retries=3, # Number of direct delivery attempts before falling back to propagation
landlock_enabled=True, # Linux Landlock LSM sandbox for the bot process (default)
external_cogs_sandbox_enabled=True, # Sandbox external script cogs on Linux
external_cogs_sandbox_type="auto", # auto, landlock, bwrap, firejail, or none
)
# Dynamically load all cogs
load_cogs_from_directory(bot)
@bot.command(name="ping", description="Test if bot is responsive")
def ping(ctx):
ctx.reply("Pong!")
# Admin Only Command
@bot.command(name="echo", description="Echo a message", admin_only=True)
def echo(ctx, message: str):
ctx.reply(message)
bot.run()
RRC (Reticulum Relay Chat)
Bots can join RRC hubs as ordinary clients over RNS Links with CBOR envelopes:
T282828
from lxmfy import LXMFBot, RRCMessage
bot = LXMFBot(
name="RoomBot",
rrc_enabled=True,
rrc_hubs=["your_rrc_hub_destination_hash"],
rrc_rooms=["lobby"],
rrc_nick="RoomBot",
)
@bot.on_rrc
def on_rrc(event, client, payload):
if event == "msg" and isinstance(payload, RRCMessage) and payload.mention:
client.send_message(payload.room, f"Heard you, {payload.nick}")
bot.run()
Or connect at runtime with T383838bot.connect_rrc(hub_hash, rooms=["lobby"]).
Hub sessions persist across restarts by default (T383838rrc_persist_sessions=True). Outgoing LXMF messages are also persisted by default (T383838message_persistence_enabled=True) so a crash mid-queue does not drop them. The outbound queue is bounded (T383838message_queue_size, default 50) and drops the oldest message when full.
Propagation Node Configuration
LXMFy supports three modes for propagation node usage:
1. Manual Configuration
Set a specific propagation node by hash:
T282828
bot = LXMFBot(
name="MyBot",
propagation_fallback_enabled=True,
propagation_node="your_propagation_node_hash_here", # Manual node configuration
direct_delivery_retries=3,
)
2. Automatic Discovery (Auto-Peering)
Let the bot automatically discover and use propagation nodes from network announces:
T282828
bot = LXMFBot(
name="MyBot",
propagation_fallback_enabled=True,
autopeer_propagation=True, # Enable automatic discovery
autopeer_maxdepth=4, # Maximum hop distance for auto-peering (default: 4)
)
The bot will listen for propagation node announces and automatically peer with suitable nodes within the configured hop depth.
3. Run as Propagation Node
Your bot can act as a propagation node itself to store and forward messages:
T282828
bot = LXMFBot(
name="MyPropagationBot",
enable_propagation_node=True, # Enable propagation node mode
message_storage_limit_mb=500, # Limit storage to 500 MB (default)
)
When running as a propagation node, the bot will store messages for offline users and forward them when the recipients come online. The T383838message_storage_limit_mb prevents the bot from consuming unlimited disk space. Set to 0 for unlimited storage (not recommended).
Querying Propagation Status
You can check the current propagation configuration and discovered nodes:
T282828
status = bot.get_propagation_node_status()
print(f"Current outbound node: {status['current_outbound_node']}")
print(f"Discovered peers: {status['discovered_peers']}")
Dynamically Setting Propagation Node
You can change the propagation node at runtime:
T282828
bot.set_propagation_node("new_propagation_node_hash")
Managing Storage Limits
When running as a propagation node, you can query and adjust storage limits:
T282828
# Get current storage statistics
stats = bot.get_propagation_storage_stats()
print(f"Storage used: {stats['storage_size_mb']:.2f} MB")
print(f"Storage limit: {stats['storage_limit_mb']} MB")
print(f"Utilization: {stats['utilization_percent']:.1f}%")
print(f"Messages stored: {stats['message_count']}")
# Change storage limit at runtime
bot.set_message_storage_limit(megabytes=1000) # Set to 1 GB
Important Notes
β’ Without configuring propagation (manual, auto-peer, or running as a node), messages requiring propagation will fail
β’ You can combine modes: e.g., set a manual node AND enable auto-peering as backup
β’ When running as a propagation node, your bot can still send and receive messages normally
β’ Auto-peering respects the T383838autopeer_maxdepth setting to avoid connecting to distant nodes
Security & Sandboxing
On Linux kernels with Landlock support (5.13+), LXMFy can restrict filesystem access for the bot process and for external script cogs.
Bot process sandbox
When T383838landlock_enabled=True (default), the bot applies a Landlock LSM sandbox after startup. System paths are read-only; bot storage, config, cogs, Reticulum config, and temp directories remain writable.
T282828
bot = LXMFBot(
name="SecureBot",
landlock_enabled=True,
)
status = bot.get_landlock_status()
print(status)
Environment overrides:
β’ T383838LXMFY_LANDLOCK=0 β disable Landlock
β’ T383838LXMFY_LANDLOCK=1 β force an attempt on Linux
β’ unset β follow T383838landlock_enabled and kernel auto-detection
External script cog sandbox
Executable cogs in T383838cogs/ can run in a restricted environment when T383838external_cogs_sandbox_enabled=True (default). Set T383838external_cogs_sandbox_type to:
β’ T383838auto (default) β prefer Landlock, then T383838bwrap, then T383838firejail
β’ T383838landlock β Landlock-only via T383838preexec_fn
β’ T383838bwrap β bubblewrap read-only bind sandbox
β’ T383838firejail β firejail private profile with no network
β’ T383838none β no subprocess sandbox
See the docs for full configuration details.
Development
β’ Python 3.11+
β’ Poetry
T282828
poetry install
poetry run lxmfy run echo
Common Makefile targets:
T282828
make lint # ruff check
make typecheck # pyright lxmfy
make test # pytest
make ci # lint, typecheck, security check, test, build
Contributing
For now send ideas and issues to LXMF: T3838387cc8d66b4f6a0e0e49d34af7f6077b5a
License
Served by rngit 1.4.1 - Generated in 0.11s